/**
 * Copyright 2012 ibiblio
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.ibiblio.terasaur.lookups

import org.grails.plugins.lookups.Lookup
import org.grails.plugins.lookups.LookupValue
import groovy.util.slurpersupport.GPathResult
import java.io.File

/**
 * Import data into the lookups plugin data structures.  Currently
 * pulls data from XML files located in grails-app/conf/lookups/.
 */
class LookupValueImporter {
    private static final String _VALUE_TYPE = "string"
    private static final int _CODE_MINIMUM = 1
    private static final String _LOOKUPS_MAP_FILE = "lookups.xml"
    private Map _params

    public LookupValueImporter(Map params) {
        _params = params
    }

    /**
     * Import all lookup realms listed in the lookups.xml configuration file
     */
    public static void importAll() {
        def importFile = _getLookupConfigPath(_LOOKUPS_MAP_FILE)

        def params = [:]
        def importer
        File xmlFile

        def root = new XmlSlurper().parse(importFile)
        root.children().each {element->
            params['realm'] = element.@realm.text()
            params['codeType'] = element.@codeType.text()
            params['ordering'] = element.@ordering.text()
            params['filename'] = _getLookupConfigPath(element.@filename.text())

            xmlFile = new File(params['filename'])
            if (!xmlFile.exists()) {
                throw new Exception("Could not find lookups import file: " + xmlFile)
            }

            importer = new LookupValueImporter(params)
            importer.importXml()
        }
    }

    private static String _getLookupConfigPath(String filename) {
        // Use local path first, then global path
        def pathSearch = [
            "grails-app/conf/lookups/",
            "/etc/terasaur/lookups/"
            ]
        def dir
        def file
        def filePath

        for (Iterator iter = pathSearch.iterator(); iter.hasNext();) {
            dir = iter.next()
            filePath = dir + filename
            file = new File(filePath)
            if (file.exists()) {
                break
            }
        }
        return filePath
    }

    public void importXml() {
        // Override table names
        // TODO: There should be a way to make this work, but I haven't
        // figured it out yet. :(

        Lookup lookup = _checkOrCreateLookup()
        _importLookupValues(lookup)
    }

    protected Lookup _checkOrCreateLookup() {
        def realm = _params["realm"]
        def codeType = _params["codeType"]
        def ordering = _params["ordering"]

        // Check for item type lookup
        Lookup lookup = Lookup.findByRealm(realm)
        if (!lookup) {
            if (codeType == "integer") {
                lookup = new Lookup(realm:realm, codeType:codeType, codeMinimum:_CODE_MINIMUM,
                                    valueType:_VALUE_TYPE, ordering:ordering, internationalize:false)
            } else {
                lookup = new Lookup(realm:realm, codeType:codeType,
                                    valueType:_VALUE_TYPE, ordering:ordering, internationalize:false)
            }
            lookup.save(insert:true, flush: true, failOnError: true)
        }
        return lookup
    }

    protected _importLookupValues(Lookup lookup) {
        def root = new XmlSlurper().parse(_params["filename"])
        root.children().each {element->
            _importLookupValue(lookup, element)
        }
    }

    protected void _importLookupValue(Lookup lookup, GPathResult element) {
        def realm = _params["realm"]
        def codeType = _params["codeType"]
        def ordering = _params["ordering"]

        def lv
        def code
        def sequencer = null

        if (codeType == "integer") {
            code = Integer.parseInt(element.@code.text())
        } else {
            code = element.@code.text()
        }
        def value = element.@value.text()
        if (ordering == "sequencer") {
            sequencer = Integer.parseInt(element.@sequencer.text())
        }

        if (!org.grails.plugins.lookups.Lookup.valueForCode(realm, code)) {
            if (ordering == "sequencer") {
                lv = new LookupValue(lookup:lookup, code:code, value:value, sequencer:sequencer)
            } else {
                lv = new LookupValue(lookup:lookup, code:code, value:value)
            }
            lv.save(failOnError: true, flush: true)
            assert !lv.hasErrors()
        }
    }

}
